/**
 * @fileoverview
 * This script defines a widget for fetching and displaying publications from FlyBase.
 * @author Jun Zhao
 * @requires YAHOO.util.Connect
 * @requires flyui
 * @requires flyui.flybasepub.Service
 * @requires flyui.flybasepub.Publication
 * TODO license terms
 */
 
// create a namespace if not already defined
flyui.namespace("flyui.flybasepub");

flyui.flybasepub.PublicationWidget = function( service, renderer ) {
	try {
		var that = this;
		
		/** @private */
		this._controller = null;
		
		/** @private */
		this._renderer = renderer;
		
		this._model = null;
		
		this._renderer = null;
    
    	this._service = null;
		
		this._init = function() {
			// create a model
			var model = new flyui.mvcutils.GenericModel2();
			model.setDefinition(flyui.flybasepub.PublicationWidget.modelDefinition);
			
			// instantiate the controller
			this._controller = new flyui.flybasepub.PublicationWidget.Controller(model, service, this);
			
			// connect the renderer to the model
			renderer.connect(model);
		};
				
    	// do initialisation
    	this._init(service, renderer);
    } catch (error) {
        throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget", error);
    }	
};




flyui.flybasepub.PublicationWidget.prototype.findPublicationsByFlybaseGeneID = function( fbgn ) {
	// pass through to controller
	try {
		this._controller.findPublicationsByFlybaseGeneID(fbgn);
	}catch (error) {
        throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.prototype.findPublicationsByFlybaseGeneID", error);
    }
};




flyui.flybasepub.PublicationWidget.prototype.findPublicationsByGene = function( gene ) {
    // pass through to controller
    try {
        this._controller.findPublicationsByGene(gene);
    }catch (error) {
        throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.prototype.findPublicationsByGene", error);
    }
};




flyui.flybasepub.PublicationWidget.Controller = function( model, service, widget ) {
	var that = this;
	
	/**
	 * @private
	 */
	this._model = model;
	
	/**
	 * @private
	 */
	this._service = service;
	
	/**
	 * @private
	 */
	this._parent = widget;
	
	
	this._findPublicationsSuccess = function( publications ) {
		try {
			flyui.info("request success");
		
			// set the results
			that._model.set("RESULTS", publications);
			
			// set the state
			that._model.set("STATE", "READY");
		}catch (error) {
        	throw new flyui.UnexpectedException("_findPublicationsSuccess", error);
    	}

	};
	
	this._findPublicationsFailure = function( response ) {
		try {
			flyui.err("request failed, status "+response.status+" "+response.statusText);
			
			// set an error message
			var msg = "There was an error retrieving data from FlyBase, see the logs for more info. The server may be busy or down, please try again later. If this message persists, please contact the Image Bioinformatics Research Group at bioimage@mail.ontonet.org.";		
	
			that._model.set("ERRORMESSAGE", msg);
	
			// set the state
			that._model.set("STATE", "SERVERERROR");
		}catch (error) {
        	throw new flyui.UnexpectedException("_findPublicationsFailure", error);
    	}		
	};
};




/**
 * @private
 */
flyui.flybasepub.PublicationWidget.Controller.prototype._limit = 100;
    



flyui.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByFlybaseGeneID = function( flybaseGeneID ) {
    // pass through to controller
    try {
        // pass through to private implementation
        this._findPublicationsByFlybaseGeneID(flybaseGeneID, this._findPublicationsSuccess, this._findPublicationsFailure);
    }catch (error) {
            throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByFlybaseGeneID", error);
    }
};





flyui.flybasepub.PublicationWidget.Controller.prototype._findPublicationsByFlybaseGeneID = function( flybaseGeneID, success, failure ) {
	try {
		flyui.info("flyui.flybasepub.PublicationWidget.Controller._findPublicationsByFlybaseGeneID :: request: "+flybaseGeneID);

        // set the results to null
        this._model.set("RESULTS", null);
        		
		// set the model pending
		this._model.set("STATE", "PENDING");
		
		// set the query property
		this._model.set("QUERY", flybaseGeneID);
		
		// kick off the request
		this._service.findPubsByUniqueGeneName(flybaseGeneID, success, failure, this._limit);
		
	}catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.Controller._findPublicationsByFlybaseGeneID", error);
    }
};





flyui.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByGene = function( gene ) {
    // pass through to controller
    try {
        // pass through to private implementation
        this._findPublicationsByGene(gene, this._findPublicationsSuccess, this._findPublicationsFailure);
    }catch (error) {
            throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.Controller.prototype.findPublicationsByFlybaseGeneID", error);
    }
};





flyui.flybasepub.PublicationWidget.Controller.prototype._findPublicationsByGene = function( gene, success, failure ) {
    try {
        flyui.info("flyui.flybasepub.PublicationWidget.Controller._findPublicationsByGene :: request: "+gene.flybaseID);

        // set the results to null
        this._model.set("RESULTS", null);
                
        // set the model pending
        this._model.set("STATE", "PENDING");
        
        // set the query property
        this._model.set("QUERY", gene);
        
        // kick off the request
        this._service.findPubsByUniqueGeneName(gene.flybaseID, success, failure, this._limit);
    }catch (error) {
            throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.Controller._findPublicationsByGene", error);
    }
};





flyui.flybasepub.PublicationWidget.modelDefinition = {
	properties : [ "STATE", "RESULTS", "QUERY", "ERRORMESSAGE" ],
	
	values : {
		"STATE" : [ "PENDING", "READY", "SERVERERROR", "UNEXPECTEDERROR" ]
	},
	
	initialize : function( data ) {
		data["STATE"] = "READY";
		data["RESULTS"] = null;
		data["QUERY"] = null;
		data["ERRORMESSAGE"] = null;
	}

};

flyui.flybasepub.PublicationWidget.DefaultRenderer = function() {
	
	/** @private */
    this._canvas = null;
    
    /** @private */
    this._pendingPane = null;
    
    /** @private */
    this._resultsPane = null;
    
    /** @private */
    this._resultsSummaryPane = null;
    
    /** @private */
    this._messagePane = null;
    
    /** @private */
    this._explanationPane = null;
    
	
};

flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype.setCanvas = function( canvas ) {
    try {
	    this._canvas = $(canvas);
	    this._initCanvas();
	}catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype.setCanvas", error);
    }
};




/**
 * @private
 * TODO doc me
 */
flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._initCanvas = function() {
    var _context = "flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._initCanvas";
	try {
		flyui.debug("_initCanvas", _context);
		
		var canvas = this._canvas;
        canvas.addClass("flybasePublicationWidget");
		
	    // set up the pending pane
		var pp = $("<p class='pendingPane'>pending...</p>").hide();
        canvas.append(pp);
        this._pendingPane = pp;
	    
	    // set up the message pane
		var msp = $("<p class='messagePane'>this text should never be displayed</p>").hide();
        canvas.append(msp);
        this._messagePane = msp;    
	    	    
	    // setup results summary pane
		var rsp = $("<p class='resultsSummaryPane'>this text should never be displayed</p>").hide();
        canvas.append(rsp);
        this._resultsSummaryPane = rsp;
	    
	    // setup results pane
		var rp = $("<div class='resultsPane'></div>").hide();
        canvas.append(rp);
        this._resultsPane = rp;

	    // setup explanation pane
        var ep = $("<p class='explanationPane'>this text should never be displayed</p>").hide();
        canvas.append(ep);
        this._explanationPane = ep;    
	    
	} catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._initCanvas", error);
    }
};




flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onModelChanged = function(type, args, self) {
    var _context = "flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onModelChanged";
    try {
	    var handlers = {
	        "STATE":"_onStateChanged",
	        "QUERY":"_onQueryChanged",
	        "RESULTS":"_onResultsChanged",
	        "ERRORMESSAGE":"_onErrorMessageChanged"
	    };
	    var handler = handlers[type];
	    flyui.debug("handler: "+handler, _context);
	    // call the handler
	    self[handler](args[0], args[1], args[2]);
	}catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onModelChanged", error);
    }
};




flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onStateChanged = function( from, to, get ) {
	var _context = "flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onStateChanged";
	try {
	    if ( to == "PENDING" ) {
            this._pendingPane.show();
            this._messagePane.empty().hide();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();
            this._explanationPane.hide();
            
		} else if (to == "READY") {
		    this._pendingPane.hide();
            this._messagePane.hide(); // hide for now, not needed yet
            this._resultsSummaryPane.show();
            this._resultsPane.show();     
            
		}else if ( to == "SERVERERROR" || to == "UNEXPECTEDERROR" ) {
		    this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide(); 
            this._explanationPane.hide();
		} 
		else {
		    // this should never happen
	    	throw {name:"flyui.flybasepub.PublicationWidget.UnexpectedStateError", message:"Invalid state: "+newState};
		}
	} catch (error) {
        	throw new flyui.UnexpectedException(_context, error);
    }
};

flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onQueryChanged = function( from, to ) {
	try {
    	// store query
    	this._query = to;
    }catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onQueryChanged", error);
    }
};


flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onResultsChanged = function( from, to ) {
	var _context = "flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onResultsChanged";	
	try {
        flyui.debug("empty results summary and explanation panes", _context);
        
        if (to == null) {

	        this._resultsPane.empty();
	        this._resultsSummaryPane.empty();
	        this._explanationPane.empty();
	        
	    } else {

	        flyui.debug("collect publications in results", _context);
	        
	        flyui.debug("empty results summary pane", _context);
            this._resultsSummaryPane.empty();
            flyui.debug("empty results pane", _context);
            this._resultsPane.empty();
            
            flyui.debug("render results summary", _context);
		    this._renderResultsSummary(this._query, to.length);
		    
		    if (to.length > 0) {
		        flyui.debug("render the results "+to.length, _context);
		        //this._resultsPane.innerHTML = this._publicationsToDivHTML(to);
		        this._renderResults(to); 
		
		    }
		    else {
	//	        flyui.info("hide results and explanation panes", _context);
	//	        flyui.mvcutils.hide(this._resultsPane);
	//            flyui.mvcutils.hide(this._explanationPane);
		    }
	    }
	} catch (error) {
        	throw new flyui.UnexpectedException(_context, error);
    }
};


flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onErrorMessageChanged = function( from, to) {
    try {
    	this._messagePane.innerHTML = to;
    }catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._onErrorMessageChanged", error);
    }
};


flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype.connect = function( model ) {
	try {
    	model.subscribeAll(this._onModelChanged, this);
    }catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype.connect", error);
    }

};




flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResultsSummary = function( query, count ) {
    var _context = "flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResultsSummary";
	try {
	    
		flyui.debug("building results summary content", _context);
		
		if (query instanceof flyui.flybase.Gene) {
		    query = query.flybaseID; // handle legacy
		}
        
        var content = "";
        
        if (count < 30) {
        	content += "found <span>";
        	content += count;
		    content += "</span> publication";
		    content += (count == 0 || count > 1) ? "s " : " ";		    
        }
        else{
        	content += "found more than 30 publications";
        	content += " (only the most recent 30 records displayed) ";	
        }
        
	    content += "from <a href='http://www.flybase.org'>www.flybase.org</a> for ";
	    content += "<a href='http://flybase.org/reports/" + query + ".html'>" + query + "</a>";
	    content += " (data retrieved on 2009-02). ";
	    
	    content += "A full list of publicaiton can be found from ";
	    content += "<a href='http://flybase.org/reports/" + query + ".html'>" + "www.flybase.org" + "</a>";
	    content += " ...";
//	    
	    //this._resultsSummaryPane.innerHTML = content;
	    this._resultsSummaryPane.html(content);
	    
	} catch (error) {
        	throw new flyui.UnexpectedException(_context, error);
    }
};





flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResults = function( publications ) {
    var _context = "flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._renderResults";
    try {
	    // build the divs
	    
	    flyui.debug("build div content for publications "+publications.length, _context);
	    
	    var pane = this._resultsPane;
	    
	    // the header
	    var content = "<table class='resultsTable'>";
	    content += "<thead><tr><th>Number</th><th>Mini Reference</th><th>Title</th><th>Year</th></tr></thead>"
	    
	    var count = 0;
	    for ( var i in publications ) {
	        if (publications[i]){
	        	if (count < 30) {
		        	var number = parseInt(i) + 1; 
		        	content += this._publicationToDivHTML(publications[i],number);
		        	flyui.debug("Generate the pub div" + content, _context);
		        	count ++;
	        	}
	        } 
	    }
	    content += "</table>";
	    //return content;
	    pane.append($(content));
	}catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._imagesToDivHTML", error);
    }
};

flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._publicationToDivHTML = function( publication, number ) {
    var _context = "flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._publicationToDivHTML";
  	try {
	    flyui.debug("build content for each publication record"+publication.title, _context);
	    
	    var content =   "<tr>";
	    content +=	"<td>" + number + "</td>" ;	    
	    content +=	"<td>" + publication.miniref + "</td>" ;
	    content +=	"<td>" + publication.title + "</td>" ;
	    content +=	"<td>" + publication.pyear + "</td>" ;
    	content +=  "</tr>";
	    return content;
	} catch (error) {
        	throw new flyui.UnexpectedException("flyui.flybasepub.PublicationWidget.DefaultRenderer.prototype._imageToDivHTML", error);
    }
};






/*
 * ----------------------------------------------------------------
 *                        SIMPLE RENDERER
 * ----------------------------------------------------------------
 */



/**
 * @class
 * @extends flyui.flybasepub.PublicationWidget.DefaultRenderer
 */
flyui.flybasepub.PublicationWidget.SimpleRenderer = function() {};




// extend
flyui.flybasepub.PublicationWidget.SimpleRenderer.prototype = new flyui.flybasepub.PublicationWidget.DefaultRenderer();





/**
 * @private
 */
flyui.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResultsSummary = function( query, count ) {
    var _context = "flyui.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResultsSummary";
    try {
        
        flyui.debug("building results summary content", _context);
        
        var content = "";
        
        content += "found " + count + " reference";
        content += (count == 0 || count > 1) ? "s " : " ";          
        content += "from <a href='http://flybase.org'>flybase.org</a> (" + flyui.flybase.provenance + ") for gene ";
        
        var n = query;
        var fbgn = query;
        
        if (query instanceof flyui.flybase.Gene) {
            n = query.symbols[0];
            fbgn = query.flybaseID;
        }

        content += "<strong>" + n + "</strong> ";

        if (count == 100) {
            content += "(only "+flyui.flybasepub.PublicationWidget.Controller.prototype._limit+" most recent results are shown, see FlyBase gene report <a href='http://flybase.org/reports/" + fbgn + ".html'>" + fbgn + "</a> for a complete list)";
        }
        else {
            content += "(FlyBase report: <a href='http://flybase.org/reports/" + fbgn + ".html'>" + fbgn + "</a>) ";
        }     
        content += " ...";

        this._resultsSummaryPane.html(content);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};




flyui.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResults = function( publications ) {
    var _context = "flyui.flybasepub.PublicationWidget.SimpleRenderer.prototype._renderResults";
    try {
        // build the divs
        
        flyui.debug("build div content for publications "+publications.length, _context);
        
        var pane = this._resultsPane;
        
        // the header
        var content = "<table class='resultsTable'>";
        content += "<tbody>"
        
        var count = 0;
        for ( var i=0; i<publications.length; i++) {
            var pub = publications[i];
            content += "<tr><td>" + pub.miniref + "<br/>" + pub.title + " [<a href='http://flybase.org/reports/"+pub.uniquename+".html'>"+pub.uniquename+"</a>]</td></tr>";
        }
        
        content += "</tbody></table>";
        //return content;
        pane.append($(content));

    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};


